using System;
using System.Linq;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Reflection;
using System.Text;
using System.Threading;
using System.Windows.Forms;
using Jabr.Logic.Roster;
using Jabr.Logic.Serialization;

namespace Jabr.GUI.Forms
{
    public partial class RosterForm : Form
    {
        static private RosterForm s_instance = null;
        static private readonly object s_padlock = new object();
        private Dictionary<string, ChatForm> m_chats;

        public static RosterForm Instance
        {
            get
            {
                lock (RosterForm.s_padlock)
                {
                    if (RosterForm.s_instance == null)
                    {
                        RosterForm.s_instance = new RosterForm();
                    }
                    return RosterForm.s_instance;
                }
            }
        }
        private RosterForm()
        {
            InitializeComponent();

            this.m_chats = new Dictionary<string, ChatForm>();

            foreach (AbstractAccount aa in RosterSingleton.Instance.AccountCollection)
            {
                DisplayableAccount da = new DisplayableAccount(aa);
                aa.Display = da;
                da.ContextMenuStrip = this.AccItemMenu;
                this.RosterTree.Nodes.Add(da);
            }

            RosterSingleton.Instance.OnAdd += delegate(AbstractAccount aa)
            {
                DisplayableAccount da = new DisplayableAccount(aa);
                aa.Display = da;
                this.RosterTree.Nodes.Add(da);
            };
            RosterSingleton.Instance.OnDelete += delegate(AbstractAccount aa)
            {
                this.RosterTree.Nodes.Remove(aa.Display);
            };
        }

        public delegate void InvokeFormDelegate(Form f);
        public void InvokeForm(Form f)
        {
            f.Show();
        }

        private void accountsToolStripMenuItem_Click(object sender, EventArgs e)
        {
            AccountAll aa = new AccountAll();
            aa.Show();
        }
        private void presenceToolStripMenuItem_Click(object sender, EventArgs e)
        {
            GenericPresence gp;
            ToolStripMenuItem c = (ToolStripMenuItem)sender;
            switch (c.Name)
            {
                default:
                case "offlineToolStripMenuItem":
                    gp = GenericPresence.OFFLINE;
                    break;
                case "invisibleToolStripMenuItem":
                    gp = GenericPresence.INVISIBLE;
                    break;
                case "freeForChatToolStripMenuItem":
                    gp = GenericPresence.FREEFORCHAT;
                    break;
                case "onlineToolStripMenuItem":
                    gp = GenericPresence.ONLINE;
                    break;
                case "awayToolStripMenuItem":
                    gp = GenericPresence.AWAY;
                    break;
                case "extendedAwayToolStripMenuItem":
                    gp = GenericPresence.XA;
                    break;
                case "doNotDisturbToolStripMenuItem":
                    gp = GenericPresence.DND;
                    break;
            }
            StatusForm sf = new StatusForm(string.Empty);
            string status = string.Empty;
            if (sf.ShowDialog() == DialogResult.OK)
                status = sf.Status;
            else
                return;
            foreach (AbstractAccount aa in RosterSingleton.Instance.AccountCollection)
            {
                aa.Status = status;
                aa.Presence = gp;
            }
        }

        private void RosterTree_MouseDown(object sender, MouseEventArgs e)
        {
            if (e.Button == MouseButtons.Right)
            {
                TreeNode tn = this.RosterTree.GetNodeAt(e.X, e.Y);
                if (tn == null)
                    return;
                this.RosterTree.SelectedNode = tn;
            }
        }
        private void RosterTree_DoubleClick(object sender, EventArgs e)
        {
            if (this.RosterTree.SelectedNode is DisplayableContact)
            {
                var p = (DisplayableContact)this.RosterTree.SelectedNode;
                if (!this.m_chats.ContainsKey(p.ContactID))
                {
                    var f = new ChatForm(p.Account, p);
                    this.m_chats.Add(p.ContactID, f);
                }
                this.m_chats[p.ContactID].Show();
            }
        }
        public void ChatFromTo(string f, string t, string msg)
        {
            DisplayableAccount a = null;
            foreach (TreeNode n in this.RosterTree.Nodes)
            {
                var ta = (DisplayableAccount)n;
                if (ta.Account.UserID == t)
                    a = ta;
            }
            DisplayableContact p = null;
            foreach (TreeNode g_c in a.Nodes)
            {
                if (g_c is DisplayableContact && ((DisplayableContact)g_c).ContactID == f)
                    p = (DisplayableContact)g_c;
                else if (g_c is DisplayableGroup)
                {
                    foreach (TreeNode n in g_c.Nodes)
                    {
                        var tp = (DisplayableContact)n;
                        if (tp.ContactID == f)
                            p = tp;
                    }
                }
            }
            if (!this.m_chats.ContainsKey(p.ContactID))
            {
                var cf = new ChatForm(p.Account, p);
                this.m_chats.Add(p.ContactID, cf);
            }
            this.m_chats[p.ContactID].ChatFrom(msg);
            this.Invoke(new RosterForm.InvokeFormDelegate(this.InvokeForm), this.m_chats[p.ContactID]);
        }

        private void removeToolStripMenuItem_Click(object sender, EventArgs e)
        {
            var dc = (DisplayableContact)this.RosterTree.SelectedNode;
            if (MessageBox.Show("Do you want to remove: " + dc.Text, "Confirm", MessageBoxButtons.YesNo, MessageBoxIcon.Question, MessageBoxDefaultButton.Button2) == DialogResult.Yes)
                dc.Delete();
        }
        private void subscribeToolStripMenuItem_Click(object sender, EventArgs e)
        {
            var dc = (DisplayableContact)this.RosterTree.SelectedNode;
            dc.Subscribe();
        }
        private void unsubscribeToolStripMenuItem_Click(object sender, EventArgs e)
        {
            var dc = (DisplayableContact)this.RosterTree.SelectedNode;
            dc.Unsubscribe();
        }
        private void moveToolStripMenuItem_Click(object sender, EventArgs e)
        {
            var dc = (DisplayableContact)this.RosterTree.SelectedNode;
            var f = new TextForm();
            f.TextValue.Text = dc.ContactName;
            if (f.ShowDialog() == DialogResult.OK)
                dc.ContactName = f.TextValue.Text;
        }

        private void groupToolStripMenuItem_Click(object sender, EventArgs e)
        {
            var tf = new TextForm();
            tf.Text = "Add group";
            if (tf.ShowDialog() == DialogResult.OK)
            {
                var da = this.RosterTree.SelectedNode;
                var dg = new DisplayableGroup(tf.TextValue.Text);
                dg.ContextMenuStrip = this.GrpItemMenu;
                da.Nodes.Add(dg);
            }
        }
        private void RosterTree_ItemDrag(object sender, ItemDragEventArgs e)
        {
            if (e.Item is DisplayableAccount || e.Item is DisplayableGroup)
                return;
            this.DoDragDrop(e.Item, DragDropEffects.All);
        }
        private void RosterTree_DragOver(object sender, DragEventArgs e)
        {
            var tn = this.RosterTree.GetNodeAt(this.RosterTree.PointToClient(new Point(e.X, e.Y)));
            if((tn is DisplayableGroup || tn is DisplayableAccount) && e.Data.GetDataPresent(typeof(DisplayableContact)))
                e.Effect = DragDropEffects.Move;
            else
                e.Effect = DragDropEffects.None;
        }
        private void RosterTree_DragEnter(object sender, DragEventArgs e)
        {
            e.Effect = DragDropEffects.Move;
        }
        private void RosterTree_DragDrop(object sender, DragEventArgs e)
        {
            if (e.Effect == DragDropEffects.Move)
            {
                var dg = this.RosterTree.GetNodeAt(this.RosterTree.PointToClient(new Point(e.X, e.Y)));
                var dc = (DisplayableContact)e.Data.GetData(typeof(DisplayableContact));
                if (dg is DisplayableGroup)
                    dc.GroupAdd((DisplayableGroup)dg);
                else
                    dc.GroupRemove();
            }
        }
        private void renameToolStripMenuItem_Click(object sender, EventArgs e)
        {
            var dg = (DisplayableGroup)this.RosterTree.SelectedNode;
            var tf = new TextForm();
            tf.TextValue.Text = dg.Text;
            tf.Text = "Rename group";
            if (tf.ShowDialog() == DialogResult.OK)
                dg.GroupName = tf.TextValue.Text;
        }
        private void deleteToolStripMenuItem_Click(object sender, EventArgs e)
        {
            var dg = (DisplayableGroup)this.RosterTree.SelectedNode;
            dg.Delete();
        }

        private void contactToolStripMenuItem_Click(object sender, EventArgs e)
        {
            var da = (DisplayableAccount)this.RosterTree.SelectedNode;
            DisplayableContact dc = new DisplayableContact();
            var cf = new ContactForm(dc);
            if (cf.ShowDialog() == DialogResult.OK)
            {
                dc.ContextMenuStrip = this.CntItemMenu;
                dc.Account = da.Account;
                da.Nodes.Add(dc);
                dc.IsInitialized = true;
                dc.Add();
            }
        }
        private void statusToolStripMenuItem_Click(object sender, EventArgs e)
        {
            
        }

        private void TrayIcon_DoubleClick(object sender, EventArgs e)
        {
            if (this.Visible)
                this.Hide();
            else
                this.Show();
        }
    }
}